package com.superb.common.database.handler;

import com.superb.common.core.annotation.SuperbEncryptDecrypt;
import com.superb.common.core.annotation.SuperbEncryptDecryptField;
import com.superb.common.core.enums.EncryptType;
import com.superb.common.utils.AesUtils;
import com.superb.common.utils.DesensitizedUtils;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 加密处理类
 * @Author: ajie
 * @CreateTime: 2024-05-11 14:51
 */
public class SuperbParamsEncryptHandler {

    /**
     * 是否启用加密
     *
     * @param object
     * @return
     */
    public static boolean isEncryptDecrypt(Object object) {
        Class<?> objectClass = object.getClass();
        return isEncryptDecrypt(objectClass);
    }


    /**
     * 获取实体对象获取加解密属性
     *
     * @param entity
     * @param <T>
     * @return
     */
    public static <T> List<EncryptDecryptModel> getEncryptDecryptFields(T entity) {
        return getEncryptDecryptFields(entity.getClass());
    }

    /**
     * 加解密实体属性缓存
     */
    private static final Map<Class<?>, List<EncryptDecryptModel>> ENCRYPT_DECRYPT_CACHE = new ConcurrentHashMap<>();

    /**
     * 获取实体对象获取加解密属性
     *
     * @param aClass
     * @param <T>
     * @return
     */
    public static <T> List<EncryptDecryptModel> getEncryptDecryptFields(Class<?> aClass) {
        if (!ENCRYPT_DECRYPT_CACHE.containsKey(aClass)) {
            synchronized (aClass.toString().intern()) {
                if (!ENCRYPT_DECRYPT_CACHE.containsKey(aClass)) {
                    List<EncryptDecryptModel> list = new ArrayList<>();
                    for (Field field : aClass.getDeclaredFields()) {
                        if (field.isAnnotationPresent(SuperbEncryptDecryptField.class)) {
                            SuperbEncryptDecryptField encryptDecryptField = field.getAnnotation(SuperbEncryptDecryptField.class);
                            list.add(new EncryptDecryptModel(field, encryptDecryptField.encrypt(), encryptDecryptField.decrypt(), encryptDecryptField.type()));
                        }
                    }
                    ENCRYPT_DECRYPT_CACHE.put(aClass, list);
                }
            }
        }
        return ENCRYPT_DECRYPT_CACHE.get(aClass);
    }

    /**
     * 是否启用加密
     * @param objectClass 获取实体上是否存在注解加密注解
     * @return
     */
    public static boolean isEncryptDecrypt(Class<?> objectClass) {
        return objectClass.isAnnotationPresent(SuperbEncryptDecrypt.class);
    }

    public static void encryptHandler(Object result, String decryptKey) throws IllegalAccessException {
        if (result instanceof ArrayList<?> resultList) {
            if (!CollectionUtils.isEmpty(resultList)) {
                Object e = resultList.get(0);
                // 如果该类存在加密注解
                if (isEncryptDecrypt(e)) {
                    encryptListEntity(resultList, decryptKey);
                }
            }
        } else {
            if (isEncryptDecrypt(result)) {
                encryptEntity(result, decryptKey);
            }
        }
    }

    private static void encryptListEntity(ArrayList<?> resultList, String decryptKey) throws IllegalAccessException {
        for (Object o : resultList) {
            encryptEntity(o, decryptKey);
        }
    }

    public static <T> void encryptEntity(T entity, String decryptKey) throws IllegalAccessException {
        List<EncryptDecryptModel> encryptDecryptModels = getEncryptDecryptFields(entity);
        for (EncryptDecryptModel encryptDecryptModel : encryptDecryptModels) {
            if (encryptDecryptModel.isEncrypt()) {
                encryptEntityField(encryptDecryptModel, entity, decryptKey);
            }
        }
    }

    /**
     * 字段加密
     * @param encryptDecryptModel 字段内容 注解和字段
     * @param result 实体信息
     * @param <T>
     */
    private static <T> void encryptEntityField(EncryptDecryptModel encryptDecryptModel, T result, String decryptKey) throws IllegalAccessException {
        Field field = encryptDecryptModel.getField();
        field.setAccessible(true);
        Object value = field.get(result);
        // 默认加密，有注解就加密
        if (value instanceof String) {
            field.set(result, AesUtils.encrypt(value.toString(), decryptKey));
        }
    }

    /**
     * 解密
     *
     * @param result sql查询结果集
     * @throws IllegalAccessException
     */
    public static void decryptHandler(Object result, String decryptKey, boolean isDesensitized) throws IllegalAccessException {
        if (result instanceof ArrayList<?> resultList) {
            if (!CollectionUtils.isEmpty(resultList)) {
                Object e = resultList.get(0);
                if (isEncryptDecrypt(e)) {
                    decryptListEntity(resultList, decryptKey, isDesensitized);
                }
            }
        } else {
            if (isEncryptDecrypt(result)) {
                decryptEntity(result, decryptKey, isDesensitized);
            }
        }
    }

    private static void decryptListEntity(ArrayList<?> resultList, String decryptKey, boolean isDesensitized) throws IllegalAccessException {
        for (Object o : resultList) {
            decryptEntity(o, decryptKey, isDesensitized);
        }
    }

    private static void decryptList(ArrayList<?> resultList, Method method, String decryptKey) {
        Map<String, Boolean> decryptMethodMap = getDecryptMethodMap(method);
        if (!CollectionUtils.isEmpty(decryptMethodMap)) {
            for (Object o : resultList) {
                decryptMap((Map) o, method, decryptKey);
            }
        }
    }

    private static void decryptEntity(Object result, String decryptKey, boolean isDesensitized) throws IllegalAccessException {
        List<EncryptDecryptModel> encryptDecryptModels = getEncryptDecryptFields(result);
        for (EncryptDecryptModel encryptDecryptModel : encryptDecryptModels) {
            decryptEntityField(encryptDecryptModel, result, decryptKey, isDesensitized);
        }
    }

    private static void decryptEntityField(EncryptDecryptModel encryptDecryptModel, Object result, String decryptKey, boolean isDesensitized) throws IllegalAccessException {
        Field field = encryptDecryptModel.getField();
        field.setAccessible(true);
        Object value = field.get(result);
        if (!Objects.isNull(value)) {
            if (value instanceof String) {
                value = field.get(result);
                if (isDesensitized) {
                    // 如果需要解密，则显示
                    if (encryptDecryptModel.isDecrypt()) {
                        // 解密后脱敏
                        field.set(result, DesensitizedUtils.desensitized(AesUtils.decrypt(value.toString(), decryptKey), encryptDecryptModel.getEncryptType()));
                    } else if (!encryptDecryptModel.isEncrypt()) {
                        // 不加密，也需要脱敏
                        field.set(result, DesensitizedUtils.desensitized(value.toString(), encryptDecryptModel.getEncryptType()));
                    }
                } else {
                    // 如果需要解密，则显示
                    if (encryptDecryptModel.isDecrypt()) {
                        field.set(result, AesUtils.decrypt(value.toString(), decryptKey));
                    } else if (!encryptDecryptModel.isEncrypt()) {
                        field.set(result, value.toString());
                    }
                }
            }
        }
    }

    private static void decryptMap(Map result, Method method, String decryptKey) {
        Map<String, Boolean> decryptMethodMap = getDecryptMethodMap(method);
        if (!CollectionUtils.isEmpty(decryptMethodMap)) {
            for (Object key : result.keySet()) {
                Object value = result.get(key);
                if (!Objects.isNull(value)) {
                    if (value instanceof String) {
                        value = result.get(key);
                        result.put(key, AesUtils.decrypt(value.toString(), decryptKey));
                    }
                }
            }
        }

    }

    /**
     * 根据方法获取解密map
     */
    private static final Map<Method, Map<String, Boolean>> DECRYPT_METHOD_CACHE = new ConcurrentHashMap<>();

    private static Map<String, Boolean> getDecryptMethodMap(Method method) {
        if (!DECRYPT_METHOD_CACHE.containsKey(method)) {
            synchronized (method.toString().intern()) {
                if (!DECRYPT_METHOD_CACHE.containsKey(method)) {
                    Map<String, Boolean> decryptMethodMap = new HashMap<>(16);
                    DECRYPT_METHOD_CACHE.put(method, decryptMethodMap);
                }
            }
        }
        return DECRYPT_METHOD_CACHE.get(method);
    }


    /**
     * 实体加解密Model
     */
    @Data
    @AllArgsConstructor
    public static class EncryptDecryptModel {
        /**
         * 属性
         */
        private Field field;

        /**
         * 加密
         */
        private boolean encrypt;

        /**
         * 解密
         */
        private boolean decrypt;

        /**
         * 加密类型
         */
        private EncryptType encryptType;
    }
}
